package com.bitcola.security.otc.biz;

import com.alicp.jetcache.anno.CacheType;
import com.alicp.jetcache.anno.Cached;
import com.bitcola.security.otc.Vo.OtcInfo;
import com.bitcola.security.common.biz.BaseBiz;
import com.bitcola.security.common.exception.LackBalanceException;
import com.bitcola.security.common.util.Snowflake;
import com.bitcola.security.otc.config.Constant;
import com.bitcola.security.otc.entity.Merchant;
import com.bitcola.security.otc.entity.OtcOrder;
import com.bitcola.security.otc.entity.PayWay;
import com.bitcola.security.otc.mapper.MerchantMapper;
import com.bitcola.security.otc.mapper.OtcOrderMapper;
import com.bitcola.security.otc.mapper.PayWayMapper;
import com.bitcola.security.otc.mapper.UserBalanceMapper;
import org.apache.commons.lang3.StringUtils;
import org.apache.ibatis.session.RowBounds;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Transactional;
import tk.mybatis.mapper.entity.Example;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;


@Service
public class OtcOrderBiz extends BaseBiz<OtcOrderMapper, OtcOrder> {


    public static BigDecimal price = BigDecimal.valueOf(7.3);
    @Resource
    PayWayMapper payWayMapper;
    @Resource
    UserBalanceMapper balanceMapper;


    @Resource
    MerchantMapper merchantMapper;

    @Cached(cacheType = CacheType.LOCAL, expire = 20)
    public PayWay getMerchant(String merchantId) {
        Example example = new Example(PayWay.class);
        example.createCriteria().andEqualTo("userId", merchantId);
        return payWayMapper.selectOneByExample(example);

    }

    public PayWay getUserPay(String userId) {
        Example example = new Example(Merchant.class);
        example.createCriteria().andEqualTo("userId", userId);
          var merchant= merchantMapper.selectOneByExample(example);
        var payway= payWayMapper.selectOneByExample(example);
          if(merchant!=null) payway.setUserType("merchant");

        return payway;

    }


    Snowflake snowflake = new Snowflake(5, 2);

    @Transactional

    public OtcInfo userBuy(String userId, BigDecimal number, String payWay,String merchantId) {
        var info = mapper.info(userId);

        Merchant merchant=merchantMapper.selectByPrimaryKey(merchantId);
        OtcInfo otcInfo= preJudge(userId, merchantId);
        if(otcInfo!=null) return otcInfo;
        var merchantPayMent = getMerchant(merchant.getUserId());
        var merchantInfo = mapper.info(merchantPayMent.getUserId());
        var userPay = getUserPay(userId);

        OtcOrder otcOrder = OtcOrder.builder().id(snowflake.nextIdStr()).
                merchantTel(merchantInfo.getTel_phone()).userTel(info.getTel_phone()).
                number(number).status(Constant.UNPAY).payway(payWay).build();
        otcOrder.setUserId(userId);
        otcOrder.setPrice(merchant.getSellPrice());
        otcOrder.setType("buy");
        otcOrder.setMerchantId(merchantId);
        otcOrder.setTime(new Date());
        if (payWay.equals(Constant.ALIPAY)) {
            if (userPay.getAlipay() == null) return OtcInfo.builder().status(202).data("请完成支付宝账号绑定").build();

            otcOrder.setUserAccount(userPay.getAlipay());
            otcOrder.setMerchantAccount(merchantPayMent.getAlipay());
        } else if (payWay.equals(Constant.WEIXIN)) {
            if (userPay.getWeixin() == null) return OtcInfo.builder().status(202).data("请完成微信账号绑定").build();
            otcOrder.setUserAccount(userPay.getWeixin());
            otcOrder.setMerchantAccount(merchantPayMent.getWeixin());
        } else return null;
        int tag=balanceMapper.reduceUserBanlance(merchant.getUserId(),"USDT",number,null);
        if(tag==0) return OtcInfo.builder().status(202).data("商户余额不足").build();
        mapper.insert(otcOrder);
        return OtcInfo.builder().status(200).data(otcOrder).build();
    }

    @Transactional
    public OtcInfo userSell(String userId,BigDecimal number,String merchantId,String payWay)
    {
        Merchant merchant=merchantMapper.selectByPrimaryKey(merchantId);

        OtcInfo otcInfo= preJudge(userId, merchantId);
           if(otcInfo!=null) return otcInfo;
        var info = mapper.info(userId);
        var userPay = getUserPay(userId);

        var merchantInfo = mapper.info(merchant.getUserId());
        if (number.compareTo(BigDecimal.valueOf(30))<0) return OtcInfo.builder().status(202).data("最小卖币数量为30U").build();



           OtcOrder otcOrder=OtcOrder.builder().id(snowflake.nextIdStr()).number(number).type("sell").
                   merchantTel(merchantInfo.getTel_phone()).
                   merchantId(merchantId).price(merchant.getBuyPrice()).time(new Date()).status(Constant.UNPAY).
                   userTel(info.getTel_phone()).build();
        var merchantPayMent = getMerchant(merchant.getUserId());
        otcOrder.setUserId(userId);
        otcOrder.setPayway(payWay);

        if (payWay.equals(Constant.ALIPAY)) {
            if (userPay.getAlipay() == null) return OtcInfo.builder().status(202).data("请完成支付宝账号绑定").build();

            otcOrder.setUserAccount(userPay.getAlipay());
            otcOrder.setMerchantAccount(merchantPayMent.getAlipay());
        } else if (payWay.equals(Constant.WEIXIN)) {
            if (userPay.getWeixin() == null) return OtcInfo.builder().status(202).data("请完成微信账号绑定").build();
            otcOrder.setUserAccount(userPay.getWeixin());
            otcOrder.setMerchantAccount(merchantPayMent.getWeixin());
        } else return null;
        int tag=balanceMapper.reduceUserBanlance(userId,"USDT",number,null);
        if(tag==0) return OtcInfo.builder().status(202).data("余额不足").build();

        mapper.insert(otcOrder);
        return OtcInfo.builder().status(200).data(otcOrder).build();


    }

    private OtcInfo preJudge(String userId, String merchantId) {
        var info = mapper.info(userId);
        if (!("LV1_PASS").equals(info.getKyc())) {
            return OtcInfo.builder().status(201).data("请完成kyc认证").build();
        }
        if (StringUtils.isEmpty(info.getTel_phone())) return OtcInfo.builder().status(201).data("请先绑定手机号").build();
        ;
        Example example=new Example(OtcOrder.class);

        example.createCriteria().andEqualTo("userId",userId);
        var orders= mapper.selectByExample(example);
        var count= orders.stream().filter(x->{ return  (x.getStatus()==null||x.getStatus().equals(Constant.UNPAY)||x.getStatus().equals(Constant.PENDING)||x.getStatus().equals(Constant.PAYED));}).count();
        if(count>0)             return OtcInfo.builder().status(201).data("存在尚未完成的订单,请忽重复下单").build();
        return null;
    }

    @Transactional

    public OtcInfo bindPayWay(String userId, String account, String payWay) {
        var info = mapper.info(userId);
        if (StringUtils.isEmpty(info.getTel_phone())) return OtcInfo.builder().status(201).data("请先绑定手机号").build();
        ;
        if (!"LV1_PASS".equals(info.getKyc())) {
            return OtcInfo.builder().status(201).data("请完成kyc认证").build();
        }




        var userPay = getUserPay(userId);
        if (userPay == null) {
            userPay = PayWay.builder().userId(userId).build();
            payWayMapper.insertSelective(userPay);
        }

        if (payWay.equals(Constant.ALIPAY)) {
            userPay.setAlipay(account);


        } else if (payWay.equals(Constant.WEIXIN)) {
            userPay.setWeixin(account);

        } else return null;

        payWayMapper.updateByPrimaryKey(userPay);
        return OtcInfo.builder().status(200).data(userPay).build();


    }

    @Transactional(isolation = Isolation.REPEATABLE_READ)
    public OtcInfo merchantPending(String orderId) {
        var order = mapper.selectForUpdate(orderId);

        if (order.getStatus().equals(Constant.PAYED)) {
            order.setStatus(Constant.PENDING);
        }
        mapper.updateByPrimaryKey(order);
        return OtcInfo.builder().status(200).data(order).build();

    }


    @Transactional(isolation = Isolation.REPEATABLE_READ)

    public OtcInfo userPayed(String userId, String orderId) {
        var order = mapper.selectByPrimaryKey(orderId);
        if (order.getUserId().equals(userId)) {
            if (order.getStatus().equals(Constant.UNPAY)) {
                order.setStatus(Constant.PAYED);
                mapper.updateByPrimaryKey(order);

            }
        }
        return OtcInfo.builder().status(200).data(order).build();
    }
    @Transactional(isolation = Isolation.REPEATABLE_READ)

    public OtcInfo userCancel(String userId, String orderId) {
        var order = mapper.selectForUpdate(orderId);
        if (order.getUserId().equals(userId)) {
            if (order.getStatus().equals(Constant.UNPAY)) {
                order.setStatus(Constant.CANCELED);
                mapper.updateByPrimaryKey(order);
                balanceMapper.addUserBanlance(order.getMerchantId(),"USDT",order.getNumber(),null);

            }
        }
        return OtcInfo.builder().status(200).data(order).build();
    }
    @Transactional
    public OtcInfo merchantPayed(String userId, String orderId) {
        var order = mapper.selectForUpdate(orderId);
        if (order.getMerchantId().equals(userId)) {
            if (order.getStatus().equals(Constant.UNPAY)) {
                order.setStatus(Constant.PAYED);
                mapper.updateByPrimaryKey(order);


            }
        }
        return OtcInfo.builder().status(200).data(order).build();
    }
    @Transactional

    public OtcInfo merchantCancel(String userId, String orderId) {
        var order = mapper.selectForUpdate(orderId);
        if (order.getMerchantId().equals(userId)) {
            if (order.getStatus().equals(Constant.UNPAY)) {
                order.setStatus(Constant.CANCELED);
                balanceMapper.addUserBanlance(order.getUserId(),"USDT",order.getNumber(),null);

                mapper.updateByPrimaryKey(order);

            }
        }
        return OtcInfo.builder().status(200).data(order).build();
    }

    @Cached(cacheType = CacheType.LOCAL,expire = 10)
    public List<Merchant>getMerchant()
    {
       return   merchantMapper.selectAll();

    }


    @Transactional
    public Boolean changeOnline(String userId){
        Example example=new Example(Merchant.class);
        example.createCriteria().andEqualTo("userId",userId);
        Merchant merchant=         merchantMapper.selectOneByExample(example);
        if(merchant!=null){
            merchant.setIsOnline(!merchant.getIsOnline());
            merchantMapper.updateByPrimaryKey(merchant);
            return  merchant.getIsOnline();
        }
        return null;


    }


    public Boolean getMerchantOnline(String userId)
    {
        Example example=new Example(Merchant.class);
        example.createCriteria().andEqualTo("userId",userId);
        Merchant merchant=         merchantMapper.selectOneByExample(example);
        if(merchant==null) return false;
        return merchant.getIsOnline();
    }




    @Transactional
    public OtcInfo userFinished(String orderId){
        var order = mapper.selectForUpdate(orderId);
        if (order.getStatus().equals(Constant.PAYED)) {

            var merchant = getMerchant(order.getMerchantId());
            var merchantId = merchant.getUserId();

             balanceMapper.addUserBanlance(merchantId, "USDT", order.getNumber(), null);

            order.setStatus(Constant.FINISHED);
            mapper.updateByPrimaryKey(order);
        }else return OtcInfo.builder().status(201).data("该订单状态已经不可改变").build();;
        return OtcInfo.builder().status(200).data(order).build();

    }

    @Transactional
    public OtcInfo merchantFail(String orderId) {
        var order = mapper.selectForUpdate(orderId);

        if (order.getStatus().equals(Constant.PENDING)) {
            order.setStatus(Constant.FAIL);
        }
        mapper.updateByPrimaryKey(order);
        balanceMapper.addUserBanlance(order.getMerchantId(), "USDT", order.getNumber(), null);

        return OtcInfo.builder().status(200).data(order).build();

    }


    @Transactional
    public OtcInfo merchantFinished(String orderId) throws LackBalanceException{
        var order = mapper.selectForUpdate(orderId);
        if (order.getStatus().equals(Constant.PENDING)) {

            var merchant = getMerchant(order.getMerchantId());

            balanceMapper.addUserBanlance(order.getUserId(),"USDT",order.getNumber(),null);
            order.setStatus(Constant.FINISHED);
        }else return OtcInfo.builder().status(201).data("该订单状态已经不可改变").build();;
        mapper.updateByPrimaryKey(order);
        return OtcInfo.builder().status(200).data(order).build();

    }

    public List<OtcOrder>getList(String userId, int page, int size,String status,String id,String merchantId,String type,String tel)
    {
        Example example=new Example(OtcOrder.class);
        var crt= example.createCriteria();
        if(StringUtils.isNotEmpty(userId)&&StringUtils.isEmpty(merchantId)){
            crt.andEqualTo("userId",userId);
        }
        if(StringUtils.isNotEmpty(status)){
            crt.andEqualTo("status",status);

        }
        if(StringUtils.isNotEmpty(id)){
            crt.andEqualTo("id",id);

        }
        if(StringUtils.isNotEmpty(merchantId)){
            crt.andEqualTo("merchantId",merchantId);

        }
        if(StringUtils.isNotEmpty(type)){
            crt.andEqualTo("type",type);

        }
        if(StringUtils.isNotEmpty(tel)){
            crt.andEqualTo("userTel",tel);

        }
        example.orderBy("time").desc();
        return mapper.selectByExampleAndRowBounds(example,new RowBounds((page-1)*size,size));

    }


}